package ics314.ui;

import java.awt.Dimension;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import ics314.RadioStation;
import ics314.Vor;
import ics314.ui.panel.CompoundVor;
import ics314.ui.panel.SimpleVor;
import ics314.util.ArrayUtilities;

/**
 * Provides a way to simulate a VOR with user customizable
 * parameters.
 * 
 * @author Anthony Sarria
 *
 */
public class Driver {

	public static void main(String[] args) {
		
		Map<String, String> argParams = getArgParams(args);
		
		// Look for "-s" tag to decide whether or not to run in simple mode
		// Parameter overrides are only processed in simple mode
		if(args.length > 0 && ArrayUtilities.containsIgnoreCase(args, "-s")) {
			runSimpleUI(argParams);
		}
		else {
			runCompoundUI();
		}
		
		
	}
	
	/**
	 * Searches the given array for tokens starting with "--param", and adds
	 * the following assignment to a map. Outputs an error message if a param
	 * tag is malformed. While any param mapping will be accepted, only parameters:
	 * obs, radial, far, over, farChance, and overChance will be used by the GUI.
	 * 
	 * @param args Array to search through
	 * @return Map containing mappings generated by array
	 */
	private static Map<String, String> getArgParams(String[] args){
		
		// Recognized param overrides: obs, radial, far, over, farChance, overChance
		Map<String, String> map = new HashMap<>();
		List<String> matches;
		String[] tokens;
		
		matches = ArrayUtilities.getAllMatchingPrefix(args, "--param");
		for(String s : matches) {
			if(s != null) {
				try {
					s = s.split("[:]")[1];
					tokens = s.split("[=]");
					map.put(tokens[0], tokens[1]);
				}
				catch(ArrayIndexOutOfBoundsException e) {
					System.err.println("WARNING -- Malformed parameter override tag: \"" + s + "\"");
				}
			}
		}
		return map;
	}
	
	/**
	 * Creates a window and runs a "simple" version of the GUI, where the
	 * OBS is prompted for, then an image of a VOR is shown using a random
	 * radial and signal quality (which can be overrided with command line 
	 * param overrides)
	 * 
	 * @param args Mapping of param overrides
	 */
	private static void runSimpleUI(Map<String, String> args) {
		
		int obs = -1;
		
		// Process override "obs"
		if(args.get("obs") != null) {
			try {
				obs = Integer.parseInt(args.get("obs"));
				if(obs > 359 || obs < 0) {
					throw new IllegalArgumentException();
				}
			}
			catch(IllegalArgumentException e) {
				System.out.println("WARNING -- Invalid value given for obs override. Using default of user specified.");
				obs = -1;
			}
		}
		// If obs override is not found, prompt user for desired obs
		while(obs < 0) {
			try {
				String response = JOptionPane.showInputDialog("Enter desired OBS radial:", "0");
				if(response == null) {
					System.exit(0);
				}
				obs = Integer.parseInt(response);
				if(obs < 0 || obs > 359) {
					obs = -1;
					throw new NumberFormatException("Given integer not in valid range.");
				}
			}
			catch(NumberFormatException e) {
				JOptionPane.showMessageDialog(null, "Entered value must be an integer in the range 0-359", "Input error", JOptionPane.ERROR_MESSAGE);
			}
		}
		
		Random r = new Random();
		int radial;
		// Process overrice "radial"
		if(args.get("radial") != null) {
			try {
				radial = Integer.parseInt(args.get("radial"));
				if(radial < 0 || radial > 359) {
					throw new IllegalArgumentException();
				}
			}
			catch(ClassCastException | IllegalArgumentException e) {
				System.out.println("WARNING -- Invalid value given for radial override. Using default of random.");
				radial = r.nextInt(360);
			}
		}
		// If override is not found, generate random number 0-359 for radial
		else {
			radial = r.nextInt(360);
		}
		
		boolean far;
		// Process override "far"
		if(args.get("far") != null) {
			far = Boolean.getBoolean(args.get("far"));
		}
		// If far override is ont found, process "farChance" override
		else if(args.get("farChance") != null) {
			try {
				int farChance = Integer.parseInt(args.get("farChance"));
				if(farChance > 100 || farChance < 0) {
					throw new IllegalArgumentException();
				}
				far = r.nextInt(100) < farChance;
			}
			catch(IllegalArgumentException e) {
				System.out.println("WARNING -- INvalid value given for farChance. Using default of 25.");
				far = r.nextInt(100) < 25;
			}
		}
		// If farChance is not found, radio station has 25% chance of being out of range
		else {
			far = r.nextInt(100) < 25;
		}
		
		
		boolean over;
		// Process "over" override
		if(args.get("over") != null) {
			over = Boolean.getBoolean(args.get("over"));
		}
		// If over override is not found, process "overChance" override
		else if(args.get("overChance") != null) {
			try {
				int overChance = Integer.parseInt(args.get("overChance"));
				if(overChance > 100 || overChance < 0) {
					throw new IllegalArgumentException();
				}
				over = r.nextInt(100) < overChance;
			}
			catch(IllegalArgumentException e) {
				System.out.println("WARNING -- INvalid value given for overChance. Using default of 25.");
				over = r.nextInt(100) < 25;
			}
		}
		// If overChance is not found, radio station has 25% chance of being directly over station
		else {
			over = r.nextInt(100) < 25;
		}
		
		// After overrides are processed, generate test station and vor
		RadioStation radio = new RadioStation("TST", radial, far, over, null);
		Vor v = new Vor(obs, radio);
		
		try {
			SwingUtilities.invokeLater(new VorBootstrapper(new SimpleVor(v), 345, 385));
		} catch (IOException e) {
			System.err.println("ERROR -- Failed to load image resources.");
		}
	}
	
	/**
	 * Creates a window for and runs a more advanced VOR simulation.
	 * OBS, radial, and signal quality can be modified through the 
	 * generated GUI.
	 */
	private static void runCompoundUI() {
		
		RadioStation radio = new RadioStation("TST", 0, true, true, null);
		Vor v = new Vor(0, radio);
		
		try {
			SwingUtilities.invokeLater(new VorBootstrapper(new CompoundVor(v), 525, 385));
		} catch (IOException e) {
			System.err.println("ERROR -- Failed to load image resources.");
		}	
		
	}
	
	/**
	 * Provides a simple Runnable implementor to be used to create a frame with
	 * the specified panel and window dimensions.
	 * 
	 * @author Anthony Sarria
	 *
	 */
	private static class VorBootstrapper implements Runnable{
		
		private JPanel panel;
		private int windowWidth;
		private int windowHeight;
		
		/**
		 * Creates a Runnable to be used by {@link SwingUtilities#invokeLater(Runnable)} to
		 * create a frame with the given panel and with the given dimensions.
		 * 
		 * @param p Panel generated frame will contain
		 * @param w Width of frame
		 * @param h Height of frame
		 */
		private VorBootstrapper(JPanel p, int w, int h) {
			this.panel = p;
			this.windowHeight = h;
			this.windowWidth = w;
		}
		
		@Override
		public void run() {
			JFrame frame = new JFrame("Simulated VOR");
			frame.setSize(new Dimension(windowWidth, windowHeight));
			frame.setLocationRelativeTo(null);
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			frame.setResizable(false);

			frame.setVisible(true);
			frame.add(panel);
		}
		
	}
}
